from django.contrib.sites.models import Site
from django.core.exceptions      import ObjectDoesNotExist
from django.db                   import models,transaction
from django.utils.encoding       import smart_unicode
from django.utils.translation    import ugettext_lazy as _
from sitepal.sitebase.conf       import properties
from sitepal.sitebase.managers   import ResourceManager
from sitepal.sitebase.models     import Resource
from sitepal.sitebase.util       import get_superuser
from sitepal.sitetheme           import *

class ThemeManager(ResourceManager):
    _theme_cache   = {}
    _current_theme = None

    def get_by_name(self,name):
        if name == CURRENT_THEME_NAME:
            name = properties.get('site-theme-current',admin=True)
        try:
            theme = self._theme_cache[name]
        except KeyError:
            theme                   = self.get(name__exact=name)
            self._theme_cache[name] = theme
        return theme

    def get_default(self):
        return self.load_theme(DEFAULT_THEME_NAME)

    def get_current(self):
        if not self._current_theme:
            try:
                theme = self.load_theme(properties.get('site-theme-current',admin=True))
            except Exception:
                theme = self.get_default()
            self._current_theme = theme
        return self._current_theme

    def set_current(self,name):
        try:
            theme = self.get_by_name(name)
        except ObjectDoesNotExist:
            theme = self.get_default()
        self._current_theme = theme

    def load_theme(self,name):
        theme = self.get_by_name(name)
        if not theme.is_loaded:
            if theme.name == DEFAULT_THEME_NAME:
                from sitepal.sitetheme.loaders import DefaultThemeLoader
                loader = DefaultThemeLoader()
            else:
                raise ValueError,"Unsupported theme"
            loader.load(theme)
        return theme

    @transaction.commit_on_success
    def sync_database(self,submodule=None):
        if not submodule:
            try:
                obj = self.get(name__exact=DEFAULT_THEME_NAME)
            except ObjectDoesNotExist:
                obj       = self.model()
                obj.name  = DEFAULT_THEME_NAME
                obj.title = u'Default Theme'
                obj.site  = Site.objects.get_current()
                obj.owner = obj.creator = get_superuser()
            obj.origin = 'sitetheme'
            obj.full_clean()
            obj.save()

class Theme(Resource):
    title       = models.CharField(_("title"),max_length=100)
    description = models.TextField(_("description"),max_length=2048,blank=True,null=True)
    objects     = ThemeManager()

    class Meta(Resource.Meta):
        verbose_name        = _('theme')
        verbose_name_plural = _('themes')
        unique_together     = ('site','name')
        app_label           = 'sitetheme'

    def __init__(self,*args,**kwargs):
        self._headers            = None
        self._media              = None
        self._theme_render_funcs = None
        self._appl_render_funcs  = None
        self._template_prefix    = None
        super(Theme,self).__init__(*args,**kwargs)

    def __unicode__(self):
        return self.name

    def __getattr__(self,name):
        try:
            return self.get_render_function(name)
        except Exception,e:
            raise AttributeError,"{0} object has no attribute {1}".format(type(self).__name__,name)

    @property
    def template_prefix(self):
        if not self._template_prefix:
            self._template_prefix = "themes/{0}/".format(self.name)
        return self._template_prefix

    @property
    def is_loaded(self):
        return bool(self._theme_render_funcs)

    @property
    def is_current(self):
        return self._default_manager.get_current().name == self.name

    @property
    def is_default(self):
        return self.name == DEFAULT_THEME_NAME

    @property
    def headers(self):
        if not self._headers:
            headers = []
            for name,medium in self._media.iteritems():
                if medium.tag_type in ('link','script'):
                    headers.append(medium.tag)
            self._headers = tuple(headers)
        return self._headers

    def get_medium_name(self,fullname):
        if fullname.startswith(self.template_prefix):
            return fullname[len(self.template_prefix):]
        elif fullname.startswith(CURRENT_THEME_PREFIX):
            if not self.is_current:
                return None
            return fullname[len(CURRENT_THEME_PREFIX):]
        return fullname

    def get_medium(self,name):
        return self._media[self.get_medium_name(name)]

    def has_medium(self,name):
        return self.get_medium_name(name) in self._media

    def itermedia(self):
        return self._media.itervalues()

    def get_render_function(self,name):
        def wrap(func):
            def wrapper(*args,**kwargs):
                return smart_unicode(func(*args,**kwargs),strings_only=True)
            return wrapper

        if name in self._theme_render_funcs:
            func = self._theme_render_funcs[name]
        else:
            func = self._appl_render_funcs[name]
        if name.startswith('render_'):
            return wrap(func)
        return func

